package com.lagou.rpc.provider.handler;

import com.alibaba.fastjson.JSON;
import com.lagou.rpc.common.RpcRequest;
import com.lagou.rpc.common.RpcResponse;
import com.lagou.rpc.provider.anno.RpcService;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.springframework.beans.BeansException;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.InvocationTargetException;
import java.security.SecureRandom;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 1.将@RpcService注解修饰的对象进行缓存
 * 2.接收客户端请求
 * 3.根据beanName从缓存中获取调用对象
 * 4.从客户端请求中解析出方法名、参数类型和参数值
 * 5.给客户端进行响应
 */
@Component
@ChannelHandler.Sharable//通道共享
public class RpcServerHandler extends SimpleChannelInboundHandler<String> implements ApplicationContextAware {
    private final static Map<String,Object> SERVICE_BEAN_MAP = new ConcurrentHashMap<>();

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg){
        //解析消息为RpcRequest对象
        RpcRequest rpcRequest =  JSON.parseObject(msg, RpcRequest.class);
        RpcResponse rpcResponse = new RpcResponse();
        rpcResponse.setRequestId(rpcRequest.getRequestId());
        try {
            //业务处理
            Thread.sleep(new SecureRandom().nextInt(3000));
            rpcResponse.setResult(handler(rpcRequest));
        } catch (InvocationTargetException | InterruptedException e) {
            //异常处理
            e.printStackTrace();
            rpcResponse.setError(e.getMessage());
        }
        System.out.println("当前服务端响应成功,服务端地址：127.0.0.1：8898，响应结果：" + JSON.toJSONString(rpcResponse));
        //将响应结果写入通道
        channelHandlerContext.writeAndFlush(JSON.toJSONString(rpcResponse));
    }

    /**
     * 业务处理
     * @param rpcRequest
     * @return
     */
    private Object handler(RpcRequest rpcRequest) throws InvocationTargetException {

        //获取调用对象
        String beanMame = rpcRequest.getClassName();
        if( !SERVICE_BEAN_MAP.containsKey(beanMame)) {
            throw new RuntimeException("该服务对象不存在,beanName:"+beanMame);
        }
        // 获取被调用对象、方法名、参数类型和参数值
        Object serviceBean = SERVICE_BEAN_MAP.get(beanMame);
        String methodName = rpcRequest.getMethodName();
        Class<?>[] parameterTypes = rpcRequest.getParameterTypes();
        Object[] parameters = rpcRequest.getParameters();

        //Cglib反射调用
        FastClass fastClass = FastClass.create(serviceBean.getClass());
        FastMethod method = fastClass.getMethod(methodName, parameterTypes);
        Object invoke = method.invoke(serviceBean, parameters);
        return invoke;
    }

    /**
     * 缓存@RpcService注解修饰的对象
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> serviceMap = applicationContext.getBeansWithAnnotation(RpcService.class);
        if(CollectionUtils.isEmpty(serviceMap)) {
            return;
        }
        // 遍历map集合，缓存到SERVICE_BEAN_MAP中
        for (Map.Entry<String, Object> entry : serviceMap.entrySet()) {
            Object serviceBean = entry.getValue();
            if(serviceBean.getClass().getInterfaces().length == 0) {
                //业务类没有实现接口
                throw new RuntimeException("当前服务没有实现接口");
            }
            //以当前对象的类全限定名为beanName
            String beanName = serviceBean.getClass().getInterfaces()[0].getName();
            SERVICE_BEAN_MAP.put(beanName,serviceBean);

        }
    }
}
